﻿using System;
using System.Collections.Generic;

namespace Behaviours.Entities
{
  public sealed class Entity : Object, IIndex
  {
    internal EntityManager manager;
    internal List<Behaviour> components = new List<Behaviour>();
    internal List<IUpdate> updates = new List<IUpdate>();
    internal bool isActive;
    public readonly List<string> Tags = new List<string>();

    public int Index { get; set; } = -1;
    public Entity()
    {
      this.manager = EntityManager.Instance;
    }

    internal void Execute()
    {
      for (int index = 0; index < this.updates.Count; ++index)
        this.updates[index].Update();
    }

    public T AddComponent<T>() where T : Behaviour, new()
    {
      T obj = this.manager.Take<T>();
      obj.entity = this;
      this.components.Add((Behaviour) obj);
      obj.Awake();
      if (obj is IUpdate update)
        this.updates.Add(update);
      this.isActive = this.updates.Count != 0;
      return obj;
    }

    public T GetComponent<T>() where T : Behaviour
    {
      for (int index = 0; index < this.components.Count; ++index)
      {
        if (this.components[index] is T component)
          return component;
      }
      return default (T);
    }

    public T[] GetComponents<T>() where T : Behaviour
    {
      List<T> objList = new List<T>();
      for (int index = 0; index < this.components.Count; ++index)
      {
        if (this.components[index] is T component)
          objList.Add(component);
      }
      return objList.ToArray();
    }
    public Behaviour[] GetComponents()
    {
      return this.components.ToArray();
    }

    public override string ToString()
    {
      string str1 = "[";
      for (int index = 0; index < this.components.Count; ++index)
        str1 = str1 + this.components[index].GetType().Name + ",";
      string str2 = str1.TrimEnd(',') + "]";
      return this.GetType().Name + " components: " + str2;
    }
    public void Destroy()
    {
      isActive = false;
      // foreach (var component in components)
      //   component.Destroy();
      throw new NotImplementedException();
    }
        
    public void SendMessage(string msg)
    {
      foreach (var c in components)
      {
        var type = c.GetType();
        var methodInfo = type.GetMethod(msg);
        if(methodInfo != null)
          methodInfo.Invoke(c, null);
      }
    }

    public void SendMessage<T>(string msg, T parameter)
    {
      foreach (var c in components)
      {
        var type = c.GetType();
        var methodInfo = type.GetMethod(msg);
        if(methodInfo != null)
          methodInfo.Invoke(c, new object[] { parameter });
      }
    }
  }
}
